/*
 * @(#)MethodReturn.java $version 2010. 8. 11
 *
 * Copyright 2007-2010 NHN Corp. All rights Reserved. 
 * NHN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.nhncorp.usf.core.service;

import static com.nhncorp.usf.core.Constants.*;

import java.util.Map;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.nhncorp.usf.core.Constants;
import com.nhncorp.usf.core.call.Fault;
import com.nhncorp.usf.core.call.ReturnValue;
import com.nhncorp.usf.core.config.runtime.Method;
import com.nhncorp.usf.core.exception.ExceptionHandler;
import com.nhncorp.usf.core.invoker.InvocationFuture;
import com.nhncorp.usf.core.invoker.InvocationFutureListener;
import com.nhncorp.usf.core.util.ErrorUtil;
import com.nhncorp.usf.core.xwork.DefaultUsfActionInvocation;
/**
 * @author Web Platform Development Team.
 */
public class MethodReturn implements ResultProcessor {
    Log log = LogFactory.getLog(MethodReturn.class);

    /**
     * enum
     */
    public enum ReturnType {
        returnObject, returnNull, nothing, failure
    };
    
    private Object returnObject;
    private ServiceExecutionContext context;

    /**
     * Gets the action id.
     *
     * @return the action id
     */
    public String getActionId() {
        return context.getAction().getId();
    }

    /**
     * Gets the bo id.
     *
     * @return the bo id
     */
    public String getBoId() {
        return context.getBo().getId();
    }

    /**
     * Gets the method name.
     *
     * @return the method name
     */
    public String getMethodName() {
        return context.getMethod().getName();
    }

    public Method getMethod() {
    	return context.getMethod();
    }
    
    /**
     * Instantiates a new method return.
     *
     * @param returnObject the return object
     * @param context      the context
     */
    public MethodReturn(Object returnObject, ServiceExecutionContext context) {
        this.context = context;
        this.returnObject = returnObject;
    }

    /**
     * Finish.
     *
     * @throws Exception the exception
     */
    public void finish() throws Exception {
        if (!(returnObject instanceof InvocationFuture)) {
            return;
        }

        Object result = ((InvocationFuture)returnObject).getReturnValue();

        if (result instanceof ReturnValue) {
            success((ReturnValue)result, context);
        } else if (result instanceof Fault) {
            failure((Fault)result, context);
        }
    }

    /**
     * @param fault   Fault
     * @param context ServiceExecutionContext
     * @throws Exception the Exception
     * @see com.nhncorp.usf.core.service.ResultProcessor#failure(com.nhncorp.lucy.net.call.Fault, com.nhncorp.usf.core.service.ServiceExecutionContext)
     */
    @SuppressWarnings("unchecked")
    public void failure(Fault fault, ServiceExecutionContext context) throws Exception {
        context.setReturnType(ReturnType.failure);
        ExceptionHandler exceptionHandler = context.getExceptionHandler();
        Map<String, String> exceptionData = (Map<String, String>)fault.getDetail();
        context.setAttribute(EXCEPTION_DATA, exceptionData);
        String exceptionClassName = ErrorUtil.getProperties(fault.getMessage()).get("classname");
        context.setAttribute(DefaultUsfActionInvocation.KEY_FAILURE_CODE, exceptionClassName);
        String errorCode = fault.getCode();
        String errorCodeNew = ErrorUtil.getProperties(fault.getMessage()).get("code");

        if (errorCodeNew != null) {
            errorCode = errorCodeNew;
        }

        context.setAttribute(Constants.KEY_ERROR_CODE, errorCode);
        exceptionHandler.handle(fault, context);
    }

    /**
     * @param returnValue ReturnValue
     * @param context     ServiceExecutionContext
     * @see com.nhncorp.usf.core.service.ResultProcessor#success(com.nhncorp.lucy.net.call.ReturnValue, com.nhncorp.usf.core.service.ServiceExecutionContext)
     */
    public void success(ReturnValue returnValue, ServiceExecutionContext context) {
        Method method = context.getMethod();

        if (returnValue == ReturnValue.VOID) {
            context.setReturnType(ReturnType.nothing);

            if (log.isDebugEnabled()) {
                log.debug("return type of method is void.");
            }

            return;
        } else {
            if (returnValue == ReturnValue.NULL) {
                context.setReturnType(ReturnType.returnNull);

                if (log.isDebugEnabled()) {
                    log.debug("return-id(" + method.getReturnId() + "), return-value is null.");
                }

                return;
            }

            if (log.isDebugEnabled()) {
                log.debug("=============== Return Value ================");
                log.debug("Type is " + returnValue.get().getClass());
                log.debug(returnValue.get());
                log.debug("=============================================");
            }

            context.setAttribute(method.getReturnId(), returnValue.get());
        }
    }

    /**
     * Adds the future listener.
     *
     * @param invocationFutureListener the invocation future listener
     * @throws MethodReturnException the method return exception
     */
    public void addFutureListener(InvocationFutureListener invocationFutureListener) throws MethodReturnException {
        if (returnObject instanceof InvocationFuture) {
            ((InvocationFuture)returnObject).addListener(invocationFutureListener);
            return;
        }

        throw new MethodReturnException("ReturnObject is not InvocationFuture.");
    }
}
